package com.spring.cloud.eurekaclientgateway.filter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.resilience4j.ratelimiter.RateLimiter;
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
import io.vavr.control.Try;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import com.spring.cloud.commonutils.vo.UserInfo;
import com.spring.cloud.commonutils.vo.ResultMessage;

import javax.xml.transform.Result;
import java.sql.ResultSet;
import java.util.concurrent.Callable;

//自定义的resilience4j的限速器过滤器
//@Component
public class RateLimiterFilter {


    //resilience4j 注册机
//    @Autowired
    private RateLimiterRegistry rateLimiterRegistry;

    //获取一个resilience4j 的限速器 ratelimiter
    private ResultMessage rateLimiter(){

        RateLimiter rateLimiter = rateLimiterRegistry.rateLimiter("user");
        Callable<ResultMessage> call = RateLimiter.decorateCallable(rateLimiter,()-> new ResultMessage(true,"PASS"));
        Try<ResultMessage> tryResult = Try.of(()->call.call())
                .recover(ex->new ResultMessage(false,"TOO MANY REQUESTS"));
        ResultMessage result = tryResult.get();
        return result;
    }

    //返回响应之后的Gateway
    //此局部过滤器也可以通过实现 GatewayFilter接口
    public GatewayFilter customGatewayFilter(){

        return (exchange, chain) -> {
            //执行 Resilience4j限速器
            ResultMessage  resultMessage = rateLimiter();
            //不放行逻辑
            if(!resultMessage.isSuccess()){
                //获取响应对象
                ServerHttpResponse response = exchange.getResponse();
                //设置响应状态码429--请求过多
                response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
                //设置响应头 类型为json
                response.getHeaders().setContentType(MediaType.valueOf(MediaType.APPLICATION_JSON_VALUE));
                //转JSON
                String body = toJson(resultMessage);
                //响应数据放入缓冲区
                DataBuffer dataBuffer = response.bufferFactory().wrap(body.getBytes());
                //使用限流结果响应请求,不在继续执行过滤器链
                return response.writeWith(Mono.just(dataBuffer));
            }
            //放行,继续执行过滤器链
            return chain.filter(exchange);
        };
    }

    //全局过滤器 因为返回GlobalFilter类型会自动识别
    //因为不需要手动调用直接使用Bean添加到ioc中
    //全局过滤器 优先于 Gateway过滤器
    //此全局过滤器也可以通过实现 GlobalFilter接口
//    @Bean
    public GlobalFilter customGlobalFilter(){
        //Lambda表达式
        return (exchange, chain) -> {
            //判定请求头token 参数是否存在
            boolean flag = !StringUtils.isBlank(exchange.getRequest().getHeaders().getFirst("token"));
            if(flag){
                //存在,直接放行路由
                return chain.filter(exchange);
            }
            //获取token参数
            String token = exchange.getRequest().getQueryParams().getFirst("token");
            ServerHttpRequest request = null;
            //token参数不为空,路由时将它放入请求头
            if(!StringUtils.isBlank(token)){
                //构建请求头                     //mutate变异
                request = exchange.getRequest().mutate().header("token",token).build();
                //构造请求头后执行责任链
                return chain.filter(exchange.mutate().request(request).build());
            }
            //放行
            return chain.filter(exchange);
        };
    }

    //ResultMessage对象转JSON
    private String toJson(ResultMessage result)  {
        ObjectMapper mapper = new ObjectMapper();
        String body = null;
        try{
            body = mapper.writeValueAsString(result);
        }catch (JsonProcessingException ex){
            ex.printStackTrace();
        }
        return body;
    }
}
